<?php

namespace common\service;

use common\model\AttributeModel;
use common\model\CheckListModel;
use common\model\ProjectTemplateModel;
use common\model\ReviewWorkflowModel;
use common\model\StepModel;
use common\model\StepReviewWorkflowRelationModel;
use common\model\StepWorkflowModel;

class StepReviewWorkflowRelationService
{

    /**
     * 查询审核流匹配数据树
     * @param array $filter
     * @param int[] $page
     * @return array|false|mixed|string
     */
    public function selectReviewRelationTree($filter = [], $page = [1, 500])
    {
        $projectTemplateList = model(ProjectTemplateModel::class)->field('id,name,code')->select();
        $workflows = model(StepWorkflowModel::class)->where($filter)->field('id,name,config,"workflow" as type')->page(...$page)->select();
        $stepList = model(StepModel::class)->field('id,name,code,"step" as type')->select();
        $stepList = array_column($stepList, null, 'code');
        $attributeList = model(AttributeModel::class)->select();
        $attributeMap = array_column($attributeList, null, 'code');
        $thirdLevelIndex = 0;

        $checkListList = model(CheckListModel::class)->field("*,'check_list' as type")->select();
        $checkListList = array_group_by($checkListList, 'project_template_id', 'step_workflow_id', 'step_id');

        $reviewWorkflowList = model(ReviewWorkflowModel::class)->field('id,name,config')->select();
        $reviewWorkflowList = array_map(function ($item) {
            return CommonService::getFormatAttrData(model(ReviewWorkflowModel::class), $item);
        }, $reviewWorkflowList);
        $reviewWorkflowList = array_column($reviewWorkflowList, null, 'id');
        $reviewWorkflowRelationList = model(StepReviewWorkflowRelationModel::class)->select();
        $reviewWorkflowRelationList = array_group_by($reviewWorkflowRelationList, 'project_template_id', 'step_workflow_id', 'step_id');

        $stepWorkflowService = StepWorkflowService::getInstance();
        foreach ($projectTemplateList as &$projectTemplate) {
            $projectTemplateId = $projectTemplate['id'];
            foreach ($workflows as &$workflow) {
                $workflow['type'] = 'step_workflow';
                $stepWorkflowId = $workflow['id'];
                $config = json_decode($workflow['config'], true);
                unset($workflow['config']);
                foreach ($config['nodes'] as $nodeList) {
                    foreach ($nodeList as $node) {
                        if (!isset($stepList[$node['module_code']])) {
                            // 工序不存在
                            continue;
                        }
                        $tmpStepInfo = $stepList[$node['module_code']];
                        $tmpStepInfo['type'] = 'step';
                        $tmpStepInfo['project_template_id'] = $projectTemplateId;
                        $tmpStepInfo['step_workflow_id'] = $stepWorkflowId;

                        $currentCheckList = $checkListList[$projectTemplateId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                        $currentReviewWorkflowList = $reviewWorkflowRelationList[$projectTemplateId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                        $currentReviewWorkflowList = array_column($currentReviewWorkflowList, null, 'attr_str');

                        if (array_key_exists('config', $node) && count($node['config']) > 0) {
                            $currentCheckList = array_group_by($currentCheckList, 'attr_str');
                            foreach ($node['config'] as $rules) {
                                list($res, $attrKeyList) = $stepWorkflowService->getNodeConfigCombinedAttrList($rules);
                                foreach ($res as $attrBind) {
                                    $thirdLevelIndex += 1;
                                    $str = '';
                                    foreach ($attrBind as $attrVK => $attrV) {
                                        $str .= $attributeMap[$attrKeyList[$attrVK]]['name'] . ":" . $attrV . '-';
                                    }
                                    $str = trim($str, '-');
                                    $tmpAttrCombined = ['id' => $thirdLevelIndex, 'project_template_id' => $projectTemplateId, 'step_workflow_id' => $stepWorkflowId, 'step_id' => $tmpStepInfo['id'], 'name' => $str, 'type' => 'attr_combined'];
                                    $tmpAttrCombined['children'] = $currentCheckList[$str] ?? [];
                                    $tmpAttrCombined['review_workflow'] = null;
                                    $reviewWorkflowRelation = $currentReviewWorkflowList[$str] ?? null;
                                    if (!empty($reviewWorkflowRelation)) {
                                        $tmpAttrCombined['review_workflow'] = $reviewWorkflowList[$reviewWorkflowRelation['review_workflow_id']] ?? null;
                                    }
                                    $tmpStepInfo['children'][] = $tmpAttrCombined;
                                }
                            }
                        } else {
                            $tmpStepInfo['review_workflow'] = null;
                            $reviewWorkflowRelation = $currentReviewWorkflowList[''] ?? null;
                            if (!empty($reviewWorkflowRelation)) {
                                $tmpStepInfo['review_workflow'] = $reviewWorkflowList[$reviewWorkflowRelation['review_workflow_id']] ?? null;
                            }
                            $tmpStepInfo['children'] = $currentCheckList;
                        }
                        $workflow['children'][] = $tmpStepInfo;
                    }
                }
            }
            $projectTemplate['type'] = 'project_template';
            $projectTemplate['children'] = $workflows;
        }
        return $projectTemplateList;
    }

    /**
     * 查询审核流匹配数据树
     * @param int $projectTemplateId 项目模板id
     * @param int $stepWorkflowId
     * @return array
     * @throws \Exception
     */
    public function selectProjectTemplateStepWorkflowReviewRelationTree(int $projectTemplateId, int $stepWorkflowId)
    {
        $workflow = model(StepWorkflowModel::class)->field('id,name,step_workflow_config as config,"workflow" as type')->find($stepWorkflowId);
        $stepList = model(StepModel::class)->field('id,id as step_id,name,code,"step" as type,"" as attr_str')->select();
        $stepList = array_column($stepList, null, 'code');
        $attributeList = model(AttributeModel::class)->select();
        $attributeMap = array_column($attributeList, null, 'code');
        $thirdLevelIndex = 0;

        $checkListList = model(CheckListModel::class)->field("*,'check_list' as type")->where(['project_template_id' => $projectTemplateId, 'step_workflow_id' => $stepWorkflowId])->select();
        $checkListList = array_map(function ($item) {
            $item['review_role_config'] = explode(',', $item['review_role_config']);
            $item['check_role_nodes'] = [];
            return $item;
        }, $checkListList);
        $checkListList = array_group_by($checkListList, 'project_template_id', 'step_workflow_id', 'step_id');

        $reviewWorkflowList = model(ReviewWorkflowModel::class)->field('id,name,config')->select();
        $roleCodes = [];
        $reviewWorkflowList = array_map(function ($item) use (&$roleCodes) {
            $item = CommonService::getFormatAttrData(model(ReviewWorkflowModel::class), $item);
            foreach ($item['config']['nodes']['reviewer'] as $reviewNode) {
                $roleCodes[$reviewNode['role']] = $reviewNode['role'];
            }

            return $item;
        }, $reviewWorkflowList);
        $roleNameMap = [];
        if (!empty($roleCodes)) {
            $roleFilter = ['param' => [
                'filter' => [
                    'role.code' => ['-in', array_values($roleCodes)],
                ],
            ]];
            $roleList = teamones_request('teamones-im', 'role/select', $roleFilter)['data']['rows'];
            $roleNameMap = array_column($roleList, 'name', 'code');
        }
        $reviewWorkflowList = array_column($reviewWorkflowList, null, 'id');
        $reviewWorkflowRelationList = model(StepReviewWorkflowRelationModel::class)->where(['project_template_id' => $projectTemplateId, 'step_workflow_id' => $stepWorkflowId])->select();
        $reviewWorkflowRelationList = array_group_by($reviewWorkflowRelationList, 'project_template_id', 'step_workflow_id', 'step_id');

        $stepWorkflowService = StepWorkflowService::getInstance();
        $workflow['type'] = 'step_workflow';
        $stepWorkflowId = $workflow['id'];
        $config = json_decode($workflow['config'], true);
        unset($workflow['config']);
        foreach ($config['nodes'] as $nodeList) {
            foreach ($nodeList as $node) {
                if (!isset($stepList[$node['module_code']])) {
                    // 工序不存在
                    continue;
                }
                $tmpStepInfo = $stepList[$node['module_code']];
                $tmpStepInfo['type'] = 'step';
                $tmpStepInfo['project_template_id'] = $projectTemplateId;
                $tmpStepInfo['step_workflow_id'] = $stepWorkflowId;

                $currentCheckList = $checkListList[$projectTemplateId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                $currentReviewWorkflowList = $reviewWorkflowRelationList[$projectTemplateId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                $currentReviewWorkflowList = array_column($currentReviewWorkflowList, null, 'attr_str');

                if (array_key_exists('config', $node) && !empty($node['config'])) {
                    $currentCheckList = array_group_by($currentCheckList, 'attr_str');
                    foreach ($node['config'] as $rules) {
                        list($res, $attrKeyList) = $stepWorkflowService->getNodeConfigCombinedAttrList($rules);
                        foreach ($res as $attrBind) {
                            $thirdLevelIndex += 1;
                            $str = '';
                            foreach ($attrBind as $attrVK => $attrV) {
                                $str .= $attributeMap[$attrKeyList[$attrVK]]['name'] . ":" . $attrV . '-';
                            }
                            $str = trim($str, '-');
                            $tmpAttrCombined = ['id' => $thirdLevelIndex, 'project_template_id' => $projectTemplateId, 'step_workflow_id' => $stepWorkflowId, 'step_id' => $tmpStepInfo['id'], 'name' => $str, 'attr_str' => $str, 'type' => 'attr_combined'];
                            $tmpAttrCombined['children'] = $currentCheckList[$str] ?? [];
                            $tmpAttrCombined['review_workflow'] = null;
                            $tmpAttrCombined['review_workflow_relation'] = $currentReviewWorkflowList[$str] ?? null;
                            $tmpAttrCombined['review_workflow_nodes'] = [];
                            if (!empty($tmpAttrCombined['review_workflow_relation'])) {
                                $tmpAttrCombined['review_workflow'] = $reviewWorkflowList[$tmpAttrCombined['review_workflow_relation']['review_workflow_id']] ?? null;
                                if (!empty($tmpAttrCombined['review_workflow'])) {
                                    foreach ($tmpAttrCombined['review_workflow']['config']['nodes']['reviewer'] as $reviewNode) {
                                        $tmpAttrCombined['review_workflow_nodes'][] = [
                                            'role_code' => $reviewNode['role'],
                                            'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                            'user_id' => 0,
                                            'user_info' => null,
                                        ];
                                        foreach ($tmpAttrCombined['children'] as &$currentAttrCheckList) {
                                            $currentAttrCheckList['check_role_nodes'][] = [
                                                'role_code' => $reviewNode['role'],
                                                'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                                'is_check' => in_array($reviewNode['role'], $currentAttrCheckList['review_role_config'])
                                            ];
                                        }
                                    }
                                }
                            }
                            $tmpStepInfo['children'][] = $tmpAttrCombined;
                        }
                    }
                } else {
                    $tmpStepInfo['children'] = $currentCheckList;
                    $tmpStepInfo['review_workflow'] = null;
                    $tmpStepInfo['review_workflow_relation'] = $currentReviewWorkflowList[''] ?? null;
                    $tmpStepInfo['review_workflow_nodes'] = [];
                    if (!empty($tmpStepInfo['review_workflow_relation'])) {
                        $tmpStepInfo['review_workflow'] = $reviewWorkflowList[$tmpStepInfo['review_workflow_relation']['review_workflow_id']] ?? null;
                        if (!empty($tmpStepInfo['review_workflow'])) {
                            foreach ($tmpStepInfo['review_workflow']['config']['nodes']['reviewer'] as $reviewNode) {
                                $tmpStepInfo['review_workflow_nodes'][] = [
                                    'role_code' => $reviewNode['role'],
                                    'role_cname' => $roleNameMap[$reviewNode['role']] ?? '未知',
                                    'user_id' => 0,
                                    'user_info' => null,
                                ];
                                foreach ($tmpStepInfo['children'] as &$currentStepCheckList) {
                                    $currentStepCheckList['check_role_nodes'][] = [
                                        'role_code' => $reviewNode['role'],
                                        'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                        'is_check' => in_array($reviewNode['role'], $currentStepCheckList['review_role_config'])
                                    ];
                                }
                            }
                        }
                    }
                }
                $workflow['children'][] = $tmpStepInfo;
            }
        }
        return $workflow['children'];
    }

    /**
     * 保存关联关系
     * @param array $relationData
     * @return array|bool
     * @throws \Exception
     */
    public function saveRelation(array $relationData)
    {
        $where = [
            'project_template_id' => $relationData['project_template_id'],
            'step_workflow_id' => $relationData['step_workflow_id'],
            'step_id' => $relationData['step_id'],
            'attr_str' => $relationData['attr_str'],
        ];
        $existData = model(StepReviewWorkflowRelationModel::class)->where($where)->find();
        if (!empty($existData)) {
            $relationData['id'] = $existData['id'];
            $res = model(StepReviewWorkflowRelationModel::class)->modifyItem($relationData);
        } else {
            $res = model(StepReviewWorkflowRelationModel::class)->addItem($relationData);
        }
        return $res;
    }

    /**
     * 批量设置工序流
     * @param array $relationDataList
     * @return array
     * @throws \Exception
     */
    public function saveProjectTemplateReviewRelation(array $relationDataList)
    {
        $where = [
            '_logic' => 'or',
        ];
        foreach ($relationDataList as $relationData) {
            $where[] = [
                'project_template_id' => $relationData['project_template_id'],
                'step_workflow_id' => $relationData['step_workflow_id'],
                'step_id' => $relationData['step_id'],
                'attr_str' => $relationData['attr_str'],
            ];
        }
        $existDataList = model(StepReviewWorkflowRelationModel::class)->where($where)->select();
        $existDataList = array_index_by($existDataList, '_', 'project_template_id', 'step_workflow_id', 'step_id', 'attr_str');

        $checkList = model(CheckListModel::class)->where($where)->select();
        $checkList = array_group_by($checkList, 'project_template_id', 'step_workflow_id', 'step_id', 'attr_str');

        $relationDataList = array_index_by($relationDataList, '_', 'project_template_id', 'step_workflow_id', 'step_id', 'attr_str');

        $reviewWorkflowList = model(ReviewWorkflowModel::class)->where(['id' => ['IN', array_unique(array_column($relationDataList, 'review_workflow_id'))]])->field("id,JSON_UNQUOTE(JSON_EXTRACT(config,'$.nodes.reviewer')) as reviewer_config")->select();
        $reviewWorkflowList = array_map(function ($item) {
            $item['config'] = json_decode($item['reviewer_config'], true);
            $item['reviewer_codes'] = implode(',', array_column($item['config'], 'role'));
            return $item;
        }, $reviewWorkflowList);
        $reviewWorkflowList = array_column($reviewWorkflowList, 'reviewer_codes', 'id');

        $addDataList = [];
        $res = [];
        $res['relation_updated'] = 0;

        $updateCheckListCodeData = [];
        foreach ($relationDataList as $key => $relationData) {
            $existData = $existDataList[$key] ?? 0;
            if (isset($relationData['review_node_config'])) {
                $relationData['review_node_config'] = json_encode($relationData['review_node_config']);
            }
            if (!empty($existData)) {
                $res['relation_updated'] += model(StepReviewWorkflowRelationModel::class)->where(['id' => $existData['id']])->save($relationData);

            } else {
                $relationData['uuid'] = create_uuid();
                $addDataList[] = $relationData;
            }

            $existCheckList = $checkList[$relationData['project_template_id']][$relationData['step_workflow_id']][$relationData['step_id']][$relationData['attr_str']] ?? [];
            if (count($existCheckList) > 0) {
                $checkListIdList = array_column($existCheckList, 'id');
                if (!isset($updateCheckListCodeData[$relationData['review_workflow_id']])) {
                    $updateCheckListCodeData[$relationData['review_workflow_id']] = [];
                }
                array_unshift($updateCheckListCodeData[$relationData['review_workflow_id']], ...$checkListIdList);
            }
        }
        $res['check_list'] = 0;
        if (count($updateCheckListCodeData) > 0) {
            foreach ($updateCheckListCodeData as $reviewWorkflowId => $checkListIdList) {
                $reviewCodes = $reviewWorkflowList[$reviewWorkflowId];
                $res['check_list'] += model(CheckListModel::class)->where(['id' => ['IN', $checkListIdList]])->save(['review_role_config' => $reviewCodes]);
            }
        }

        if (count($addDataList) > 0) {
            $res['relation_added'] = model(StepReviewWorkflowRelationModel::class)->addAll($addDataList);
        }
        return $res;
    }

    /**
     * 保存审核点审核角色code数据
     * @param $dataList
     * @return bool|int|string
     * @throws \Exception
     */
    public function saveCheckListRoleCode($dataList)
    {
        $res = 0;
        $dataListGrouped = array_group_by($dataList, 'review_role_config');
        foreach ($dataListGrouped as $reviewRoleConfig => $dataList) {
            $checklistIdList = array_column($dataList, 'id');
            $res += model(CheckListModel::class)->where(['id' => ['IN', $checklistIdList]])->save(['review_role_config' => $reviewRoleConfig]);
        }
        return $res;
    }
}
